<?php
/* $Id$ */
/*
	firewall_nat_edit.php
	part of m0n0wall (http://m0n0.ch/wall)

	Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
	All rights reserved.

	Redistribution and use in source and binary forms, with or without
	modification, are permitted provided that the following conditions are met:

	1. Redistributions of source code must retain the above copyright notice,
	   this list of conditions and the following disclaimer.

	2. Redistributions in binary form must reproduce the above copyright
	   notice, this list of conditions and the following disclaimer in the
	   documentation and/or other materials provided with the distribution.

	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
	POSSIBILITY OF SUCH DAMAGE.
*/

##|+PRIV
##|*IDENT=page-firewall-nat-portforward-edit
##|*NAME=Firewall: NAT: Port Forward: Edit page
##|*DESCR=Allow access to the 'Firewall: NAT: Port Forward: Edit' page.
##|*MATCH=firewall_nat_edit.php*
##|-PRIV


require("guiconfig.inc");

if (!is_array($config['nat']['rule'])) {
	$config['nat']['rule'] = array();
}
//nat_rules_sort();
$a_nat = &$config['nat']['rule'];

$id = $_GET['id'];
if (isset($_POST['id']))
	$id = $_POST['id'];

if (isset($_GET['dup'])) {
        $id = $_GET['dup'];
        $after = $_GET['dup'];
}

if (isset($id) && $a_nat[$id]) {
	$pconfig['extaddr'] = $a_nat[$id]['external-address'];
	$pconfig['proto'] = $a_nat[$id]['protocol'];
	list($pconfig['beginport'],$pconfig['endport']) = explode("-", $a_nat[$id]['external-port']);
	$pconfig['localip'] = $a_nat[$id]['target'];
	$pconfig['localbeginport'] = $a_nat[$id]['local-port'];
	$pconfig['descr'] = $a_nat[$id]['descr'];
	$pconfig['interface'] = $a_nat[$id]['interface'];
	$pconfig['nosync'] = isset($a_nat[$id]['nosync']);
	if (!$pconfig['interface'])
		$pconfig['interface'] = "wan";
} else {
	$pconfig['interface'] = "wan";
}

if (isset($_GET['dup']))
	unset($id);

/*  run through $_POST items encoding HTML entties so that the user
 *  cannot think he is slick and perform a XSS attack on the unwilling 
 */
//foreach ($_POST as $key => $value) {
//	$temp = $value;
//	$newpost = htmlentities($temp);
//	if($newpost <> $temp) 
//		$input_errors[] = "检测到无效字符 ($temp)。请删除无效字符然后再保存。";		
//}

if ($_POST) {

	if ($_POST['beginport_cust'] && !$_POST['beginport'])
		$_POST['beginport'] = $_POST['beginport_cust'];
	if ($_POST['endport_cust'] && !$_POST['endport'])
		$_POST['endport'] = $_POST['endport_cust'];
	if ($_POST['localbeginport_cust'] && !$_POST['localbeginport'])
		$_POST['localbeginport'] = $_POST['localbeginport_cust'];

	if (!$_POST['endport'])
		$_POST['endport'] = $_POST['beginport'];
        /* Make beginning port end port if not defined and endport is */
        if (!$_POST['beginport'] && $_POST['endport'])
                $_POST['beginport'] = $_POST['endport'];

	unset($input_errors);
	$pconfig = $_POST;

	/* input validation */
	if(strtoupper($_POST['proto']) == "TCP" or strtoupper($_POST['proto']) == "UDP" or strtoupper($_POST['proto']) == "TCP/UDP") {
		$reqdfields = explode(" ", "interface proto beginport endport localip localbeginport");
		$reqdfieldsn = explode(",", "接口,协议,起始外部端口,结束外部端口,NAT IP,本地端口");
	} else {
		$reqdfields = explode(" ", "interface proto localip");
		$reqdfieldsn = explode(",", "接口,协议,NAT IP");
	}

	do_input_validation($_POST, $reqdfields, $reqdfieldsn, &$input_errors);

	if (($_POST['localip'] && !is_ipaddroralias($_POST['localip']))) {
		$input_errors[] = "\"{$_POST['localip']}\" 不是有效的IP地址或别名。";
	}

	/* only validate the ports if the protocol is TCP, UDP or TCP/UDP */
	if(strtoupper($_POST['proto']) == "TCP" or strtoupper($_POST['proto']) == "UDP" or strtoupper($_POST['proto']) == "TCP/UDP") {

		if (($_POST['beginport'] && !is_ipaddroralias($_POST['beginport']) && !is_port($_POST['beginport']))) {
			$input_errors[] = "起始端口必须在 1 和 65535 之间。";
		}

		if (($_POST['endport'] && !is_ipaddroralias($_POST['endport']) && !is_port($_POST['endport']))) {
			$input_errors[] = "结束端口必须在 1 和 65535 之间。";
		}

		if (($_POST['localbeginport'] && !is_ipaddroralias($_POST['localbeginport']) && !is_port($_POST['localbeginport']))) {
			$input_errors[] = "本地端口必须在 1 和 65535 之间。";
		}

		if ($_POST['beginport'] > $_POST['endport']) {
			/* swap */
			$tmp = $_POST['endport'];
			$_POST['endport'] = $_POST['beginport'];
			$_POST['beginport'] = $tmp;
		}

		if (!$input_errors) {
			if (($_POST['endport'] - $_POST['beginport'] + $_POST['localbeginport']) > 65535)
				$input_errors[] = "目标端口必须在 1 和 65535 之间。";
		}

	}

	/* check for overlaps */
	foreach ($a_nat as $natent) {
		if (isset($id) && ($a_nat[$id]) && ($a_nat[$id] === $natent))
			continue;
		if ($natent['interface'] != $_POST['interface'])
			continue;
		if ($natent['external-address'] != $_POST['extaddr'])
			continue;
		if (($natent['proto'] != $_POST['proto']) && ($natent['proto'] != "tcp/udp") && ($_POST['proto'] != "tcp/udp"))
			continue;

		list($begp,$endp) = explode("-", $natent['external-port']);
		if (!$endp)
			$endp = $begp;

		if (!(   (($_POST['beginport'] < $begp) && ($_POST['endport'] < $begp))
		      || (($_POST['beginport'] > $endp) && ($_POST['endport'] > $endp)))) {

			$input_errors[] = "外部端口范围和已有记录重叠。";
			break;
		}
	}

	if (!$input_errors) {
		$natent = array();
		if ($_POST['extaddr'])
			$natent['external-address'] = $_POST['extaddr'];
		$natent['protocol'] = $_POST['proto'];

		if ($_POST['beginport'] == $_POST['endport'])
			$natent['external-port'] = $_POST['beginport'];
		else
			$natent['external-port'] = $_POST['beginport'] . "-" . $_POST['endport'];

		$natent['target'] = $_POST['localip'];
		$natent['local-port'] = $_POST['localbeginport'];
		$natent['interface'] = $_POST['interface'];
		$natent['descr'] = $_POST['descr'];

		if($_POST['nosync'] == "yes")
			$natent['nosync'] = true;
		else
			unset($natent['nosync']);

		if (isset($id) && $a_nat[$id])
			$a_nat[$id] = $natent;
		else {
			if (is_numeric($after))
				array_splice($a_nat, $after+1, 0, array($natent));
			else
				$a_nat[] = $natent;
		}

		touch($d_natconfdirty_path);

		if ($_POST['autoadd']) {
			/* auto-generate a matching firewall rule */
			$filterent = array();
			$filterent['interface'] = $_POST['interface'];
			$filterent['protocol'] = $_POST['proto'];
			$filterent['source']['any'] = "";
			$filterent['destination']['address'] = $_POST['localip'];

			$dstpfrom = $_POST['localbeginport'];
			$dstpto = $dstpfrom + $_POST['endport'] - $_POST['beginport'];

			if ($dstpfrom == $dstpto)
				$filterent['destination']['port'] = $dstpfrom;
			else
				$filterent['destination']['port'] = $dstpfrom . "-" . $dstpto;

			$filterent['descr'] = "NAT " . $_POST['descr'];
			/*
			 * Our firewall filter description may be no longer than
			 * 63 characters, so don't let it be.
			 */
			$filterent['descr'] = substr("NAT " . $_POST['descr'], 0, 59);

			$config['filter']['rule'][] = $filterent;

			touch($d_filterconfdirty_path);
		}

		write_config();

		header("Location: firewall_nat.php");
		exit;
	}
}

$pgtitle = array("防火墙","NAT管理","端口转发：编辑");
$pgmenu = array('nat', '/firewall_nat.php');
include("head.inc");

?>

<body link="#0000CC" vlink="#0000CC" alink="#0000CC">
<?php
include("fbegin.inc"); ?>
<?php if ($input_errors) print_input_errors($input_errors); ?>
            <form action="firewall_nat_edit.php" method="post" name="iform" id="iform">
              <table width="100%" border="0" cellpadding="6" cellspacing="0">
				<tr>
					<td colspan="2" valign="top" class="listtopic">编辑NAT规则</td>
				</tr>	
				<tr>
                  <td width="22%" valign="top" class="vncellreq">接口</td>
                  <td width="78%" class="vtable">
					<select name="interface" class="formselect">
						<?php
						
						$iflist = get_configured_interface_with_descr(false, true);
						foreach ($iflist as $if => $ifdesc) 
							if(have_ruleint_access($if)) 
								$interfaces[$if] = $ifdesc;
						
						if ($config['pptpd']['mode'] == "server")
							if(have_ruleint_access("pptp")) 
								$interfaces['pptp'] = "PPTP VPN";
						
						if ($config['pppoe']['mode'] == "server")
							if(have_ruleint_access("pppoe")) 
								$interfaces['pppoe'] = "PPPoE VPN";
						
						/* add ipsec interfaces */
						if (isset($config['ipsec']['enable']) || isset($config['ipsec']['mobileclients']['enable']))
							if(have_ruleint_access("enc0")) 
								$interfaces["enc0"] = "IPsec";						

						foreach ($interfaces as $iface => $ifacename): ?>
						<option value="<?=$iface;?>" <?php if ($iface == $pconfig['interface']) echo "selected"; ?>>
						<?=htmlspecialchars($ifacename);?>
						</option>
						<?php endforeach; ?>
					</select><br>
                     <span class="vexpl">选择规则应用的接口。<br>
                     提示：大多数情况您可能需要选择WAN。</span></td>
                </tr>
			    <tr>
                  <td width="22%" valign="top" class="vncellreq">外部地址</td>
                  <td width="78%" class="vtable">
					<select name="extaddr" class="formselect">
						<option value="" <?php if (!$pconfig['extaddr']) echo "selected"; ?>>接口地址</option>
<?php					if (is_array($config['virtualip']['vip'])):
						foreach ($config['virtualip']['vip'] as $sn): ?>
						<option value="<?=$sn['subnet'];?>" <?php if ($sn['subnet'] == $pconfig['extaddr']) echo "selected"; ?>><?=htmlspecialchars("{$sn['subnet']} ({$sn['descr']})");?></option>
<?php					endforeach;
						endif; ?>
						<option value="any" <?php if($pconfig['extaddr'] == "any") echo "selected"; ?>>任意</option>
					</select>
					<br />
                    <span class="vexpl">
					如果您需要该规则应用到接口的其他的IP上，您需要首先在
					<a href="firewall_virtual_ip.php">虚拟IP</a>中定义该接口的其他IP。</span></td>
                </tr>
                <tr>
                  <td width="22%" valign="top" class="vncellreq">协议</td>
                  <td width="78%" class="vtable">
                    <select name="proto" class="formselect" onChange="proto_change(); check_for_aliases();">
                      <?php $protocols = explode(" ", "TCP UDP TCP/UDP"); foreach ($protocols as $proto): ?>
                      <option value="<?=strtolower($proto);?>" <?php if (strtolower($proto) == $pconfig['proto']) echo "selected"; ?>><?=htmlspecialchars($proto);?></option>
                      <?php endforeach; ?>
                    </select> <br> <span class="vexpl">选择需要匹配的协议。<br>
                       提示：大多数情况您可能需要选择<em>TCP</em> &nbsp;。</span></td>
                </tr>
                <tr>
                  <td width="22%" valign="top" class="vncellreq">外部端口</td>
                  <td width="78%" class="vtable">
                    <table border="0" cellspacing="0" cellpadding="0">
                      <tr>
                        <td>from:&nbsp;&nbsp;</td>
                        <td><select name="beginport" class="formselect" onChange="ext_rep_change(); ext_change(); check_for_aliases();">
                            <option value="">(other)</option>
                            <?php $bfound = 0; foreach ($wkports as $wkport => $wkportdesc): ?>
                            <option value="<?=$wkport;?>" <?php if ($wkport == $pconfig['beginport']) {
								echo "selected";
								$bfound = 1;
							}?>>
							<?=htmlspecialchars($wkportdesc);?>
							</option>
                            <?php endforeach; ?>
                          </select> <input onChange="check_for_aliases();" autocomplete='off' class="formfldalias" name="beginport_cust" id="beginport_cust" type="text" size="5" value="<?php if (!$bfound) echo $pconfig['beginport']; ?>"></td>
                      </tr>
                      <tr>
                        <td>to:</td>
                        <td><select name="endport" class="formselect" onChange="ext_change(); check_for_aliases();">
                            <option value="">(other)</option>
                            <?php $bfound = 0; foreach ($wkports as $wkport => $wkportdesc): ?>
                            <option value="<?=$wkport;?>" <?php if ($wkport == $pconfig['endport']) {
								echo "selected";
								$bfound = 1;
							}?>>
							<?=htmlspecialchars($wkportdesc);?>
							</option>
							<?php endforeach; ?>
                          </select> <input onChange="check_for_aliases();" class="formfldalias" autocomplete='off' name="endport_cust" id="endport_cust" type="text" size="5" value="<?php if (!$bfound) echo $pconfig['endport']; ?>"></td>
                      </tr>
                    </table>
                    <br> <span class="vexpl">填写需要转发的外部地址的端口或者端口范围。<br>
                       提示：你可以让<em>'to'</em>字段留空如果你想指定一个单独的端口。</span></td>
                </tr>
                <tr>
                  <td width="22%" valign="top" class="vncellreq">NAT IP</td>
                  <td width="78%" class="vtable">
                    <input autocomplete='off' name="localip" type="text" class="formfldalias" id="localip" size="20" value="<?=htmlspecialchars($pconfig['localip']);?>">
                    <br> <span class="vexpl">填写需要端口转发的内部服务器的IP地址。<br>
                       例如<em>192.168.1.12</em></span></td>
                </tr>
                <tr>
                  <td width="22%" valign="top" class="vncellreq">本地端口</td>
                  <td width="78%" class="vtable">
                    <select name="localbeginport" class="formselect" onChange="ext_change();check_for_aliases();">
                      <option value="">(other)</option>
                      <?php $bfound = 0; foreach ($wkports as $wkport => $wkportdesc): ?>
                      <option value="<?=$wkport;?>" <?php if ($wkport == $pconfig['localbeginport']) {
							echo "selected";
							$bfound = 1;
						}?>>
					  <?=htmlspecialchars($wkportdesc);?>
					  </option>
                      <?php endforeach; ?>
                    </select> <input onChange="check_for_aliases();" autocomplete='off' class="formfldalias" name="localbeginport_cust" id="localbeginport_cust" type="text" size="5" value="<?php if (!$bfound) echo $pconfig['localbeginport']; ?>">
                    <br>
                    <span class="vexpl">填写上述IP地址的端口范围。如果是端口范围则填写起始端口。（结束端口会根据外部端口范围自动计算）<br></span></td>
                </tr>
                <tr>
                  <td width="22%" valign="top" class="vncell">描述</td>
                  <td width="78%" class="vtable">
                    <input name="descr" type="text" class="formfld unknown" id="descr" size="40" value="<?=htmlspecialchars($pconfig['descr']);?>">
                    <br> <span class="vexpl">您可以输入一些描述作为参考。</span></td>
                </tr>
                <?php if ((!(isset($id) && $a_nat[$id])) || (isset($_GET['dup']))): ?>
                <tr>
                  <td width="22%" valign="top">&nbsp;</td>
                  <td width="78%">
                    <input name="autoadd" type="checkbox" id="autoadd" value="yes" CHECKED>
                    <strong>在防火墙规则中自动添加允许符合本规则的流量。</strong></td>
                </tr><?php endif; ?>
                <tr>
                  <td width="22%" valign="top">&nbsp;</td>
                  <td width="78%">
                    <input name="Submit" type="submit" class="formbtn" value="保存"> <input type="button" class="formbtn" value="取消" onclick="history.back()">
                    <?php if (isset($id) && $a_nat[$id]): ?>
                    <input name="id" type="hidden" value="<?=$id;?>">
                    <?php endif; ?>
                  </td>
                </tr>
              </table>
</form>
<script language="JavaScript">
<!--
	ext_change();
//-->
</script>
<?php
$isfirst = 0;
$aliases = "";
$addrisfirst = 0;
$aliasesaddr = "";
if($config['aliases']['alias'] <> "")
	foreach($config['aliases']['alias'] as $alias_name) {
		if(!stristr($alias_name['address'], ".")) {
			if($isfirst == 1) $aliases .= ",";
			$aliases .= "'" . $alias_name['name'] . "'";
			$isfirst = 1;
		} else {
			if($addrisfirst == 1) $aliasesaddr .= ",";
			$aliasesaddr .= "'" . $alias_name['name'] . "'";
			$addrisfirst = 1;
		}
	}
?>
<script language="JavaScript">
<!--
	var addressarray=new Array(<?php echo $aliasesaddr; ?>);
	var customarray=new Array(<?php echo $aliases; ?>);
//-->
</script>
<?php include("fend.inc"); ?>
</body>
</html>
